#!/usr/bin/env ts-node

/**
 * Enterprise features example of @roasmax/rabbitmq
 */

import {
  RabbitMQClient,
  createMessage,
  createTypedHandler,
  createLoggingMiddleware,
  createMetricsMiddleware,
  createStructuredLoggingMiddleware,
  createPerformanceLoggingMiddleware,
  RetryHandler,
  ConditionalHandler,
} from '../src';
import { z } from 'zod';

// Define typed message schemas
const UserEventSchema = z.object({
  userId: z.string(),
  eventType: z.enum(['login', 'logout', 'purchase', 'signup']),
  timestamp: z.string(),
  metadata: z.record(z.unknown()).optional(),
});

const OrderEventSchema = z.object({
  orderId: z.string(),
  customerId: z.string(),
  amount: z.number(),
  currency: z.string(),
  items: z.array(z.object({
    productId: z.string(),
    quantity: z.number(),
    price: z.number(),
  })),
});

type UserEvent = z.infer<typeof UserEventSchema>;
type OrderEvent = z.infer<typeof OrderEventSchema>;

async function enterpriseExample(): Promise<void> {
  console.log('🏢 Enterprise RabbitMQ Example');
  console.log('==============================');

  // Create client with enterprise configuration
  const client = RabbitMQClient.create({
    host: process.env.RABBITMQ_HOST || 'localhost',
    port: parseInt(process.env.RABBITMQ_PORT || '5672'),
    username: process.env.RABBITMQ_USERNAME || 'guest',
    password: process.env.RABBITMQ_PASSWORD || 'guest',
    heartbeat: 300,
    connectionTimeout: 10000,
    maxRetries: 5,
    retryDelay: 2000,
  });

  try {
    await client.initialize();
    console.log('✅ Enterprise client initialized');

    // Setup comprehensive middleware pipeline
    const pipeline = client.getMiddlewarePipeline();
    
    // Structured logging
    pipeline.add(createStructuredLoggingMiddleware({
      sendLevel: 'debug',
      processLevel: 'info',
      errorLevel: 'error',
      includeStackTrace: true,
    }));

    // Performance monitoring
    pipeline.add(createPerformanceLoggingMiddleware(500, false)); // Log slow operations > 500ms

    // Metrics collection with reporting
    const metricsMiddleware = createMetricsMiddleware(undefined, 10000); // Report every 10 seconds
    pipeline.add(metricsMiddleware);

    console.log('✅ Middleware pipeline configured');

    // Example 1: Type-safe Message Processing
    console.log('\n🔒 Type-safe Message Processing');
    console.log('-------------------------------');

    const router = client.createRouter('events');
    await router.setupExchange();

    // User event handler with validation
    const userEventHandler = createTypedHandler(
      UserEventSchema,
      async (userEvent: UserEvent) => {
        console.log(`👤 Processing user event: ${userEvent.eventType} for user ${userEvent.userId}`);
        
        // Simulate different processing based on event type
        switch (userEvent.eventType) {
          case 'login':
            console.log(`  📊 Recording login for user ${userEvent.userId}`);
            break;
          case 'purchase':
            console.log(`  💰 Processing purchase analytics for user ${userEvent.userId}`);
            break;
          case 'signup':
            console.log(`  🎉 Welcome new user ${userEvent.userId}`);
            break;
          default:
            console.log(`  📝 Logging event ${userEvent.eventType}`);
        }

        return { processed: true, eventType: userEvent.eventType };
      }
    );

    // Order event handler with validation
    const orderEventHandler = createTypedHandler(
      OrderEventSchema,
      async (orderEvent: OrderEvent) => {
        console.log(`🛒 Processing order ${orderEvent.orderId} for customer ${orderEvent.customerId}`);
        console.log(`  💵 Amount: ${orderEvent.amount} ${orderEvent.currency}`);
        console.log(`  📦 Items: ${orderEvent.items.length}`);

        // Simulate order processing
        await new Promise(resolve => setTimeout(resolve, 200));

        return { 
          processed: true, 
          orderId: orderEvent.orderId,
          totalAmount: orderEvent.amount 
        };
      }
    );

    // Subscribe to different event types
    await router.subscribe('user.*', userEventHandler, { queueName: 'user_events' });
    await router.subscribe('order.*', orderEventHandler, { queueName: 'order_events' });

    console.log('✅ Type-safe handlers subscribed');

    // Example 2: Advanced Error Handling and Retries
    console.log('\n🔄 Advanced Error Handling');
    console.log('--------------------------');

    // Create a handler that sometimes fails
    const unreliableHandler = createTypedHandler(
      z.object({ id: z.string(), shouldFail: z.boolean().optional() }),
      async (data: { id: string; shouldFail?: boolean }) => {
        console.log(`🎲 Processing unreliable task ${data.id}`);
        
        if (data.shouldFail && Math.random() < 0.7) {
          throw new Error(`Simulated failure for task ${data.id}`);
        }

        return { processed: true, id: data.id };
      }
    );

    // Wrap with retry logic
    const retryHandler = new RetryHandler(
      unreliableHandler,
      3, // max retries
      1000, // initial delay
      2 // backoff factor
    );

    // Conditional handler - only process during business hours
    const businessHoursHandler = new ConditionalHandler();
    businessHoursHandler
      .when(
        (_) => {
          const hour = new Date().getHours();
          return hour >= 9 && hour <= 17; // 9 AM to 5 PM
        },
        retryHandler
      )
      .otherwise(createTypedHandler(
        z.object({ id: z.string() }),
        async (data) => {
          console.log(`⏰ Task ${data.id} queued for business hours`);
          return { queued: true, id: data.id };
        }
      ));

    const reliabilityQueue = client.createWorkQueue('reliability_test');
    await reliabilityQueue.setupQueue();
    await reliabilityQueue.startWorkers(businessHoursHandler, 1);

    console.log('✅ Advanced error handling configured');

    // Example 3: Send Test Messages
    console.log('\n📤 Sending Test Messages');
    console.log('------------------------');

    // Send user events
    const userEvents: UserEvent[] = [
      {
        userId: 'user_001',
        eventType: 'login',
        timestamp: new Date().toISOString(),
        metadata: { ip: '192.168.1.1', userAgent: 'Chrome/91.0' }
      },
      {
        userId: 'user_002',
        eventType: 'signup',
        timestamp: new Date().toISOString(),
        metadata: { referrer: 'google.com' }
      },
      {
        userId: 'user_001',
        eventType: 'purchase',
        timestamp: new Date().toISOString(),
        metadata: { amount: 99.99, currency: 'USD' }
      }
    ];

    for (const event of userEvents) {
      await router.send(`user.${event.eventType}`, event);
      console.log(`📤 Sent user event: ${event.eventType}`);
    }

    // Send order events
    const orderEvents: OrderEvent[] = [
      {
        orderId: 'order_001',
        customerId: 'user_001',
        amount: 149.99,
        currency: 'USD',
        items: [
          { productId: 'prod_001', quantity: 2, price: 49.99 },
          { productId: 'prod_002', quantity: 1, price: 49.99 }
        ]
      },
      {
        orderId: 'order_002',
        customerId: 'user_002',
        amount: 79.99,
        currency: 'EUR',
        items: [
          { productId: 'prod_003', quantity: 1, price: 79.99 }
        ]
      }
    ];

    for (const order of orderEvents) {
      await router.send('order.created', order);
      console.log(`📤 Sent order event: ${order.orderId}`);
    }

    // Send reliability test messages
    for (let i = 1; i <= 5; i++) {
      await reliabilityQueue.sendTask({
        id: `task_${i}`,
        shouldFail: i % 2 === 0, // Every other task should fail
      });
      console.log(`📤 Sent reliability test task ${i}`);
    }

    // Wait for processing
    console.log('\n⏳ Processing messages...');
    await new Promise(resolve => setTimeout(resolve, 8000));

    // Example 4: Metrics and Monitoring
    console.log('\n📊 Metrics and Monitoring');
    console.log('-------------------------');

    const detailedMetrics = metricsMiddleware.getDetailedMetrics();
    console.log('Basic Metrics:');
    console.log(`  📨 Messages sent: ${detailedMetrics.basic.sentCount}`);
    console.log(`  📬 Messages received: ${detailedMetrics.basic.receivedCount}`);
    console.log(`  ✅ Messages processed: ${detailedMetrics.basic.processedCount}`);
    console.log(`  ❌ Messages failed: ${detailedMetrics.basic.failedCount}`);
    console.log(`  🔄 Retries: ${detailedMetrics.basic.retryCount}`);
    console.log(`  ⏱️  Average processing time: ${detailedMetrics.basic.averageProcessingTime.toFixed(2)}ms`);

    console.log('\nPercentiles:');
    console.log(`  📊 P50: ${detailedMetrics.percentiles.p50.toFixed(2)}ms`);
    console.log(`  📊 P95: ${detailedMetrics.percentiles.p95.toFixed(2)}ms`);
    console.log(`  📊 P99: ${detailedMetrics.percentiles.p99.toFixed(2)}ms`);

    console.log('\nRates:');
    console.log(`  ✅ Success rate: ${(detailedMetrics.rates.successRate * 100).toFixed(1)}%`);
    console.log(`  ❌ Failure rate: ${(detailedMetrics.rates.failureRate * 100).toFixed(1)}%`);
    console.log(`  🔄 Retry rate: ${(detailedMetrics.rates.retryRate * 100).toFixed(1)}%`);

    console.log('\n✅ Enterprise example completed successfully!');

  } catch (error) {
    console.error('❌ Error:', error);
  } finally {
    // Clean up
    await client.close();
    console.log('🔒 Enterprise client closed');
  }
}

// Run the example
if (require.main === module) {
  enterpriseExample().catch(console.error);
}

export { enterpriseExample };
